package me.epet.car;

import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;

import me.epet.car.utils.BaiduVoiceSynthesizer;
// 新增：导入语音消息常量类
import me.epet.car.utils.VoiceMessages;

/**
 * 小车运动模拟程序
 * 功能：实现小车在网格中的手动/自动移动、方向控制、速度调节、轨迹显示、摄像头控制、目的地和障碍物标注等功能
 */
public class CarSimulation extends JFrame {

    // 固定棋盘大小
    private static final int BOARD_SIZE = 600;
    private static final int CONTROL_PANEL_WIDTH = 220; // 控制面板宽度
    private static final int WINDOW_PADDING = 60; // 增加窗口边距
    private static final int COMMAND_AREA_HEIGHT = 100; // 指令输出区域高度

    // 摄像头相关
    private static final int CAMERA_INITIAL_WIDTH = 450;  // 摄像头初始宽度
    private static final int CAMERA_INITIAL_HEIGHT = 350; // 摄像头初始高度

    // 小车状态参数
    private int logicalX = 0;        // 逻辑坐标系中的x坐标
    private int logicalY = 0;        // 逻辑坐标系中的y坐标
    private String direction = "北"; // 初始方向（北、东、南、西）
    private int speed = 1;           // 初始速度为1

    // 运动控制组件
    private Timer moveTimer;         // 用于控制移动的定时器
    private boolean isMoving = false;// 用于判断小车是否在移动
    // 轨迹与目的地
    private List<int[]> trajectory = new ArrayList<>(); // 用于记录轨迹
    private boolean showTrajectory = true;             // 用于判断是否显示轨迹
    private Point destination = null;                  // 存储目的地坐标（屏幕坐标）
    private Timer autoMoveTimer;                       // 用于自动移动的定时器
    private boolean isLightOn = false;                 // 用于判断车灯是否开启

    // 摄像头相关
    private boolean isCameraOn = false;                // 用于判断摄像头是否开启
    private JPanel cameraPanel;                        // 摄像头显示面板
    private JLabel cameraLabel;                        // 摄像头显示标签
    private OpenCVFrameGrabber grabber;                // JavaCV摄像头抓取器
    private Timer cameraTimer;                         // 摄像头刷新定时器
    private JPanel cameraControlPanel;                 // 摄像头控制面板
    private JSplitPane splitPane;                      // 分割面板

    // 控制面板组件
    private JPanel directionControlPanel; // 方向控制面板
    private JPanel speedControlPanel;
    private JPanel lightControlPanel;
    private JPanel trajectoryControlPanel;
    private JPanel advancedControlPanel;
    private JButton startStopBtn; // 启动/停止按钮引用

    // 指令输出区域组件
    private JTextArea commandOutputArea;
    private JScrollPane commandScrollPane;
    private List<String> commandHistory = new ArrayList<>();
    private static final int MAX_HISTORY_LINES = 1000; // 最多显示10条指令历史
    private JButton clearCommandBtn; // 新增：清空指令按钮

    // 标注相关
    private List<Point> obstacles = new ArrayList<>(); // 障碍物列表
    private JButton addDestinationBtn; // 添加目的地按钮
    private JButton addObstacleBtn; // 添加障碍物按钮
    private JButton resetAllBtn; // 新增：完全重置按钮
    private AnnotationMode annotationMode = AnnotationMode.NONE; // 当前标注模式

    // 新增：手动命令输入相关组件
    private JTextField commandInputField;
    private JButton sendCommandBtn;

    // 新增：语音合成相关
    private BaiduVoiceSynthesizer voiceSynthesizer;

    // 标注模式枚举
    private enum AnnotationMode {
        NONE, ADD_DESTINATION, ADD_OBSTACLE
    }

    public CarSimulation() {
        // 窗口基础设置
        setTitle("小车运动模拟");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 新增：初始化语音合成器
        voiceSynthesizer = new BaiduVoiceSynthesizer();

        // 创建主面板
        JPanel mainPanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets(10, 10, 10, 10);

        // 创建棋盘容器面板
        JPanel boardContainer = new JPanel(new BorderLayout());
        boardContainer.setBorder(BorderFactory.createTitledBorder("棋盘区域"));

        // 创建固定大小的绘图面板
        JPanel drawingPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                drawGrid(g);
                drawDestination(g);
                drawObstacles(g);
                drawCar(g);
                if (showTrajectory) {
                    drawTrajectory(g);
                }
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(BOARD_SIZE, BOARD_SIZE);
            }

            @Override
            public Dimension getMinimumSize() {
                return getPreferredSize();
            }

            @Override
            public Dimension getMaximumSize() {
                return getPreferredSize();
            }
        };
        drawingPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        // 处理地图点击事件
        drawingPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Point logicalPoint = convertToLogicalCoordinates(e.getPoint());

                switch (annotationMode) {
                    case ADD_DESTINATION:
                        destination = logicalPoint;
                        addCommand("设置目的地: (" + destination.x + ", " + destination.y + ")");
                        repaint();
                        break;
                    case ADD_OBSTACLE:
                        obstacles.add(logicalPoint);
                        addCommand("添加障碍物: (" + logicalPoint.x + ", " + logicalPoint.y + ")");
                        repaint();
                        break;
                    case NONE:
                // 修改为双击移除障碍物
                if (e.getClickCount() == 2) {
                    if (removeObstacleIfClicked(logicalPoint)) {
                        addCommand("移除障碍物: (" + logicalPoint.x + ", " + logicalPoint.y + ")");
                        repaint();
                    }
                }
                break;
                }
            }
        });

        // 将绘图面板添加到棋盘容器的中央，使其居中显示
        boardContainer.add(drawingPanel, BorderLayout.CENTER);

        // 右侧功能控制面板（方向、速度、车灯、轨迹、高级功能、摄像头、标注）
        JPanel functionPanel = new JPanel(new GridBagLayout());
        functionPanel.setBorder(BorderFactory.createTitledBorder("功能控制区域"));
        functionPanel.setPreferredSize(new Dimension(CONTROL_PANEL_WIDTH, BOARD_SIZE));
        GridBagConstraints panelGbc = new GridBagConstraints();
        panelGbc.gridx = 0;
        panelGbc.fill = GridBagConstraints.HORIZONTAL;
        panelGbc.insets = new Insets(1, 2, 1, 2);

        // 创建方向控制面板
        directionControlPanel = new JPanel(new GridBagLayout());
        directionControlPanel.setBorder(BorderFactory.createTitledBorder("方向控制"));
        GridBagConstraints dirGbc = new GridBagConstraints();
        dirGbc.fill = GridBagConstraints.CENTER;

        // 方向按钮与重置按钮
        JButton northBtn = createStyledButton("北");
        JButton westBtn = createStyledButton("西");
        JButton eastBtn = createStyledButton("东");
        JButton southBtn = createStyledButton("南");
        JButton resetBtn = createStyledButton("O");

        // 按钮布局
        dirGbc.gridx = 0; dirGbc.gridy = 0; dirGbc.gridwidth = 3;
        directionControlPanel.add(northBtn, dirGbc);

        dirGbc.gridy = 1; dirGbc.gridwidth = 1;
        directionControlPanel.add(westBtn, dirGbc);
        dirGbc.gridx = 1; directionControlPanel.add(resetBtn, dirGbc);
        dirGbc.gridx = 2; directionControlPanel.add(eastBtn, dirGbc);

        dirGbc.gridy = 2; dirGbc.gridx = 0; dirGbc.gridwidth = 3;
        directionControlPanel.add(southBtn, dirGbc);

        // 创建其他控制面板
        speedControlPanel = createControlPanel("速度控制", createStyledButton("快"), createStyledButton("慢"), false);
        lightControlPanel = createControlPanel("灯控制", createStyledButton("开"), createStyledButton("关"), false);
        trajectoryControlPanel = createControlPanel("轨迹控制", createStyledButton("开"), createStyledButton("关"), false);
        cameraControlPanel = createControlPanel("摄像头控制", createStyledButton("开"), createStyledButton("关"), false);

        // 创建高级控制面板
        startStopBtn = createStyledButton("开始");
        resetAllBtn = createStyledButton("全清"); // 新增：完全重置按钮
        advancedControlPanel = createControlPanel("高级", resetAllBtn, startStopBtn, false);

        // 创建标注添加面板
        addDestinationBtn = createStyledButton("目的地");
        addObstacleBtn = createStyledButton("障碍物");
        JPanel annotationPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        annotationPanel.setBorder(BorderFactory.createTitledBorder("标注添加"));
        annotationPanel.add(addDestinationBtn);
        annotationPanel.add(addObstacleBtn);

        // 将控制面板添加到功能面板
        panelGbc.gridy = 0;
        panelGbc.weighty = 0.2;
        functionPanel.add(directionControlPanel, panelGbc);

        panelGbc.gridy = 1;
        panelGbc.weighty = 0.1;
        functionPanel.add(speedControlPanel, panelGbc);

        panelGbc.gridy = 2;
        functionPanel.add(lightControlPanel, panelGbc);

        panelGbc.gridy = 3;
        functionPanel.add(trajectoryControlPanel, panelGbc);

        panelGbc.gridy = 4;
        functionPanel.add(cameraControlPanel, panelGbc);

        panelGbc.gridy = 5;
        functionPanel.add(advancedControlPanel, panelGbc);

        panelGbc.gridy = 6;
        functionPanel.add(annotationPanel, panelGbc);

        // 新增：创建手动命令输入面板
        JPanel commandInputPanel = new JPanel(new BorderLayout());
        commandInputPanel.setBorder(BorderFactory.createTitledBorder("手动命令输入"));
        commandInputField = new JTextField();
        sendCommandBtn = createStyledButton("发送");
        commandInputPanel.add(commandInputField, BorderLayout.CENTER);
        commandInputPanel.add(sendCommandBtn, BorderLayout.EAST);

        panelGbc.gridy = 7;
        functionPanel.add(commandInputPanel, panelGbc);

        // 主面板布局设置
        gbc.gridx = 0; gbc.weightx = 0; mainPanel.add(new JPanel(), gbc);
        gbc.gridx = 1; gbc.weightx = 4; mainPanel.add(boardContainer, gbc);
        gbc.gridx = 2; gbc.weightx = 1; mainPanel.add(functionPanel, gbc);

        // 初始化摄像头组件
        initCameraComponents();

        // 创建分割面板
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, cameraPanel, mainPanel);
        splitPane.setDividerLocation(CAMERA_INITIAL_WIDTH);
        splitPane.setResizeWeight(0.0);

        // 初始化指令输出区域
        initCommandOutputArea();

        // 将分割面板和指令输出区域添加到窗口
        add(splitPane, BorderLayout.CENTER);
        add(commandScrollPane, BorderLayout.SOUTH);

        // 定时器初始化
        moveTimer = new Timer(100, e -> {
            moveForward(speed);
            isMoving = true;
            repaint();
        });
        autoMoveTimer = new Timer(100, e -> {
            if (destination != null) {
                autoMoveToDestination();
            }
        });

        // 目的地到达监听器
        autoMoveTimer.addActionListener(e -> {
            if (destination != null &&
                    Math.abs(logicalX - destination.x) <= speed &&
                    Math.abs(logicalY - destination.y) <= speed) {
                autoMoveTimer.stop();
                startStopBtn.setText("开始");
                addCommand("到达目的地");
                // 修改：使用常量类中的到达提示文本
                voiceSynthesizer.synthesizeAndPlay(VoiceMessages.ARRIVAL_DESTINATION);
                repaint();
            }
        });

        // 设置按钮事件
        setupButtonEvents(northBtn, eastBtn, southBtn, westBtn, resetBtn);
        setupControlPanelEvents();

        // 设置标注按钮事件
        setupAnnotationButtonEvents();

        // 完全重置按钮事件
        resetAllBtn.addActionListener(e -> {
            resetAll();
            addCommand("已重置所有内容");
        });

        // 新增：命令输入按钮事件
        sendCommandBtn.addActionListener(e -> {
            String command = commandInputField.getText().trim();
            if (!command.isEmpty()) {
                processManualCommand(command);
                commandInputField.setText(""); // 清空输入框
            }
        });

        // 新增：支持回车键发送命令
        commandInputField.addActionListener(e -> {
            String command = commandInputField.getText().trim();
            if (!command.isEmpty()) {
                processManualCommand(command);
                commandInputField.setText("");
            }
        });

        // 清空指令按钮事件
        clearCommandBtn.addActionListener(e -> {
            clearCommands();
            addCommand("已清空指令输出区域");
        });

        // 计算并设置窗口大小
        pack();
        int windowWidth = CAMERA_INITIAL_WIDTH + BOARD_SIZE + CONTROL_PANEL_WIDTH + WINDOW_PADDING;
        int windowHeight = Math.max(BOARD_SIZE, CAMERA_INITIAL_HEIGHT) + COMMAND_AREA_HEIGHT + WINDOW_PADDING + 120;
        setSize(windowWidth, windowHeight);
        setLocationRelativeTo(null);
    }

    // 设置标注按钮事件
    private void setupAnnotationButtonEvents() {
        addDestinationBtn.addActionListener(e -> {
            annotationMode = annotationMode == AnnotationMode.ADD_DESTINATION ? AnnotationMode.NONE : AnnotationMode.ADD_DESTINATION;
            addCommand(annotationMode == AnnotationMode.ADD_DESTINATION ? "切换到添加目的地模式" : "退出添加目的地模式");
            updateAnnotationButtons();
        });

        addObstacleBtn.addActionListener(e -> {
            annotationMode = annotationMode == AnnotationMode.ADD_OBSTACLE ? AnnotationMode.NONE : AnnotationMode.ADD_OBSTACLE;
            addCommand(annotationMode == AnnotationMode.ADD_OBSTACLE ? "切换到添加障碍物模式" : "退出添加障碍物模式");
            updateAnnotationButtons();
        });
    }

    // 更新标注按钮状态
    private void updateAnnotationButtons() {
        // 使用更醒目的颜色表示选中状态
        Color selectedColor = new Color(231, 76, 60); // 红色系
        Color normalColor = new Color(52, 152, 219);  // 蓝色系

        addDestinationBtn.setBackground(annotationMode == AnnotationMode.ADD_DESTINATION ? selectedColor : normalColor);
        addObstacleBtn.setBackground(annotationMode == AnnotationMode.ADD_OBSTACLE ? selectedColor : normalColor);
    }

    // 检查并移除被点击的障碍物
    private boolean removeObstacleIfClicked(Point clickPoint) {
        // 定义点击检测范围（考虑障碍物大小）
        int detectionRange = 20; // 障碍物大小的一半

        for (int i = 0; i < obstacles.size(); i++) {
            Point obstacle = obstacles.get(i);
            if (Math.abs(obstacle.x - clickPoint.x) <= detectionRange &&
                    Math.abs(obstacle.y - clickPoint.y) <= detectionRange) {
                obstacles.remove(i);
                return true;
            }
        }
        return false;
    }

    // 初始化指令输出区域
    private void initCommandOutputArea() {
        // 创建指令输出区域
        commandOutputArea = new JTextArea(10, 40);
        commandOutputArea.setEditable(false);
        commandOutputArea.setFont(new Font("SimSun", Font.PLAIN, 14));

        // 创建带清空按钮的面板
        JPanel commandPanel = new JPanel(new BorderLayout());
        commandPanel.setBorder(BorderFactory.createTitledBorder("指令输出区域"));

        // 添加指令文本区域
        commandScrollPane = new JScrollPane(commandOutputArea);
        commandPanel.add(commandScrollPane, BorderLayout.CENTER);

        // 创建清空按钮
        clearCommandBtn = new JButton("清空指令");
        clearCommandBtn.setFont(new Font("Microsoft YaHei", Font.BOLD, 12));
        clearCommandBtn.setBackground(new Color(231, 76, 60)); // 红色按钮
        clearCommandBtn.setForeground(Color.WHITE);
        clearCommandBtn.setFocusPainted(false);

        // 添加按钮到面板底部
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.add(clearCommandBtn);
        commandPanel.add(buttonPanel, BorderLayout.SOUTH);

        // 将面板添加到窗口
        commandScrollPane = new JScrollPane(commandPanel);
    }

    // 清空指令输出区域
    private void clearCommands() {
        commandHistory.clear();
        commandOutputArea.setText("");
    }

    // 新增：处理手动输入命令
    private void processManualCommand(String command) {
        if (command.equals("开始")) {
            if (destination != null) {
                if (!autoMoveTimer.isRunning()) {
                    autoMoveTimer.start();
                    startStopBtn.setText("停止");
                    addCommand("开始自动移动到目的地");
                } else {
                    addCommand("小车已经在移动中");
                }
            } else {
                addCommand("请先设置目的地");
            }
        } else if (command.equals("停止")) {
            if (autoMoveTimer.isRunning()) {
                autoMoveTimer.stop();
                startStopBtn.setText("开始");
                addCommand("已停止自动移动");
            } else {
                addCommand("小车当前未在移动");
            }
        } else {
            addCommand("未知命令: " + command + "，请输入'开始'或'停止'");
        }
    }

    // 向指令输出区域添加指令
    private void addCommand(String command) {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = now.format(formatter);

        commandHistory.add("[" + formattedDateTime + "] " + command);

        if (commandHistory.size() > MAX_HISTORY_LINES) {
            commandHistory.remove(0);
        }

        StringBuilder sb = new StringBuilder();
        for (String cmd : commandHistory) {
            sb.append(cmd).append("\n");
        }
        commandOutputArea.setText(sb.toString());
        commandOutputArea.setCaretPosition(commandOutputArea.getDocument().getLength());
    }

    // 创建美化后的按钮
    private JButton createStyledButton(String text) {
        JButton button = new JButton(text);
        button.setFont(new Font("Microsoft YaHei", Font.BOLD, 14));
        button.setForeground(Color.BLACK);
        button.setBackground(new Color(52, 152, 219));
        button.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(Color.DARK_GRAY, 2),
                BorderFactory.createEmptyBorder(5, 10, 5, 10)
        ));
        button.setFocusPainted(false);
        button.setContentAreaFilled(true);
        button.setOpaque(true);

        // 添加悬停效果
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                if (annotationMode == AnnotationMode.NONE ||
                        (annotationMode == AnnotationMode.ADD_DESTINATION && !e.getComponent().equals(addDestinationBtn)) ||
                        (annotationMode == AnnotationMode.ADD_OBSTACLE && !e.getComponent().equals(addObstacleBtn))) {
                    button.setBackground(new Color(41, 128, 185));
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {
                if (annotationMode == AnnotationMode.NONE ||
                        (annotationMode == AnnotationMode.ADD_DESTINATION && !e.getComponent().equals(addDestinationBtn)) ||
                        (annotationMode == AnnotationMode.ADD_OBSTACLE && !e.getComponent().equals(addObstacleBtn))) {
                    button.setBackground(new Color(52, 152, 219));
                }
            }
        });

        return button;
    }

    // 初始化摄像头组件
    private void initCameraComponents() {
        cameraPanel = new JPanel(new BorderLayout());
        cameraPanel.setBorder(BorderFactory.createTitledBorder("摄像头区域"));

        cameraLabel = new JLabel("摄像头已关闭", JLabel.CENTER);
        cameraLabel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));

        cameraPanel.add(cameraLabel, BorderLayout.CENTER);
    }

    // 新增：创建控制面板的方法
    private JPanel createControlPanel(String title, JButton btn1, JButton btn2, boolean isVertical) {
        JPanel panel = new JPanel(isVertical ? new GridLayout(2, 1) : new FlowLayout(FlowLayout.CENTER));
        panel.setBorder(BorderFactory.createTitledBorder(title));
        panel.add(btn1);
        panel.add(btn2);
        return panel;
    }

    // 设置按钮事件
    private void setupButtonEvents(JButton northBtn, JButton eastBtn, JButton southBtn,
                                   JButton westBtn, JButton resetBtn) {
        // 方向按钮事件
        northBtn.addActionListener(e -> {
            handleDirection("北");
            addCommand("方向: 北");
            repaint();
        });
        eastBtn.addActionListener(e -> {
            handleDirection("东");
            addCommand("方向: 东");
            repaint();
        });
        southBtn.addActionListener(e -> {
            handleDirection("南");
            addCommand("方向: 南");
            repaint();
        });
        westBtn.addActionListener(e -> {
            handleDirection("西");
            addCommand("方向: 西");
            repaint();
        });
        resetBtn.addActionListener(e -> {
            reset();
            addCommand("重置方向");
        });

        // 长按移动控制
        ActionListener moveAction = e -> {
            handleDirection(direction);
            moveTimer.start();
            isMoving = true;
            addCommand("开始手动移动");
            repaint();
        };
        ActionListener stopAction = e -> {
            moveTimer.stop();
            isMoving = false;
            addCommand("停止手动移动");
            repaint();
        };

        // 方向按钮长按逻辑
        setupLongPressControl(northBtn, "北", moveAction, stopAction);
        setupLongPressControl(eastBtn, "东", moveAction, stopAction);
        setupLongPressControl(southBtn, "南", moveAction, stopAction);
        setupLongPressControl(westBtn, "西", moveAction, stopAction);
    }

    // 辅助方法：设置按钮长按事件
    private void setupLongPressControl(JButton btn, String dir,
                                       ActionListener pressAction, ActionListener releaseAction) {
        btn.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent evt) {
                direction = dir;
                pressAction.actionPerformed(null);
            }
            @Override
            public void mouseReleased(MouseEvent evt) {
                releaseAction.actionPerformed(null);
            }
        });
    }

    // 设置控制面板事件
    private void setupControlPanelEvents() {
        // 速度控制
        JButton accelerateBtn = (JButton)speedControlPanel.getComponent(0);
        JButton decelerateBtn = (JButton)speedControlPanel.getComponent(1);
        accelerateBtn.addActionListener(e -> {
            if (speed < 5) {
                speed++;
                addCommand("速度: " + speed);
                // 更新定时器间隔以反映速度变化
                if (moveTimer != null) {
                    moveTimer.setDelay(100 / speed);
                }
                if (autoMoveTimer != null) {
                    autoMoveTimer.setDelay(100 / speed);
                }
            } else {
                addCommand("已达到最大速度");
            }
        });
        decelerateBtn.addActionListener(e -> {
            if (speed > 1) {
                speed--;
                addCommand("速度: " + speed);
                // 更新定时器间隔以反映速度变化
                if (moveTimer != null) {
                    moveTimer.setDelay(100 / speed);
                }
                if (autoMoveTimer != null) {
                    autoMoveTimer.setDelay(100 / speed);
                }
            } else {
                addCommand("已达到最小速度");
            }
        });

        // 车灯控制
        JButton lightOnBtn = (JButton)lightControlPanel.getComponent(0);
        JButton lightOffBtn = (JButton)lightControlPanel.getComponent(1);
        lightOnBtn.addActionListener(e -> {
            isLightOn = true;
            addCommand("车灯: 开启");
            repaint();
        });
        lightOffBtn.addActionListener(e -> {
            isLightOn = false;
            addCommand("车灯: 关闭");
            repaint();
        });

        // 轨迹控制
        JButton showTrajBtn = (JButton)trajectoryControlPanel.getComponent(0);
        JButton hideTrajBtn = (JButton)trajectoryControlPanel.getComponent(1);
        showTrajBtn.addActionListener(e -> {
            showTrajectory = true;
            addCommand("轨迹: 显示");
            repaint();
        });
        hideTrajBtn.addActionListener(e -> {
            showTrajectory = false;
            addCommand("轨迹: 隐藏");
            repaint();
        });

        // 摄像头控制
        JButton cameraOnBtn = (JButton)cameraControlPanel.getComponent(0);
        JButton cameraOffBtn = (JButton)cameraControlPanel.getComponent(1);
        cameraOnBtn.addActionListener(e -> {
            try {
                startCamera();
                addCommand("摄像头: 开启");
            } catch (FrameGrabber.Exception ex) {
                JOptionPane.showMessageDialog(this, "无法打开摄像头: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
            repaint();
        });
        cameraOffBtn.addActionListener(e -> {
            stopCamera();
            addCommand("摄像头: 关闭");
            repaint();
        });

        // 高级控制
        JButton resetCarBtn = (JButton)advancedControlPanel.getComponent(0);
        resetCarBtn.addActionListener(e -> {
            resetCar();
            addCommand("重置小车位置");
        });

        // 启动/停止按钮事件
        startStopBtn.addActionListener(e -> {
            if (autoMoveTimer.isRunning()) {
                autoMoveTimer.stop();
                startStopBtn.setText("开始");
                addCommand("停止自动移动");
                // 新增：停止时语音反馈
                voiceSynthesizer.synthesizeAndPlay(VoiceMessages.COMMAND_STOP);
                repaint();
            } else {
                if (destination == null) {
                    JOptionPane.showMessageDialog(this, "请先设置目的地", "提示", JOptionPane.INFORMATION_MESSAGE);
                } else {
                    autoMoveTimer.start();
                    startStopBtn.setText("停止");
                    addCommand("开始自动移动");
                    // 新增：开始时语音反馈
                    voiceSynthesizer.synthesizeAndPlay(VoiceMessages.COMMAND_START);
                    repaint();
                }
            }
        });
    }

    // 启动摄像头
    private void startCamera() throws FrameGrabber.Exception {
        if (isCameraOn) return;

        cameraLabel.setText("摄像头启动中...");
        cameraPanel.add(cameraLabel, BorderLayout.CENTER);
        cameraPanel.revalidate();
        cameraPanel.repaint();

        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                try {
                    grabber = new OpenCVFrameGrabber(0);
                    grabber.start();

                    SwingUtilities.invokeLater(() -> {
                        if (cameraPanel.getComponentCount() > 0) {
                            cameraPanel.remove(0);
                        }

                        CameraCanvas cameraCanvas = new CameraCanvas();
                        cameraPanel.add(cameraCanvas, BorderLayout.CENTER);
                        cameraPanel.revalidate();
                        cameraPanel.repaint();

                        cameraTimer = new Timer(30, e -> {
                            try {
                                if (grabber != null) {
                                    Frame frame = grabber.grab();
                                    if (frame != null) {
                                        try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
                                            BufferedImage image = converter.convert(frame);
                                            cameraCanvas.setImage(image);
                                        }
                                    }
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        });

                        cameraTimer.start();
                        isCameraOn = true;
                    });
                } catch (FrameGrabber.Exception ex) {
                    SwingUtilities.invokeLater(() -> {
                        cameraLabel.setText("摄像头启动失败");
                        JOptionPane.showMessageDialog(CarSimulation.this,
                                "无法打开摄像头: " + ex.getMessage(),
                                "错误", JOptionPane.ERROR_MESSAGE);
                        stopCamera();
                    });
                    throw ex;
                }
                return null;
            }
        };

        worker.execute();
    }

    // 自定义双缓冲Canvas组件
    private class CameraCanvas extends Canvas {
        private BufferedImage image;
        private BufferedImage offscreenImage;
        private Graphics2D offscreenGraphics;
        private double aspectRatio = 1.0;

        public CameraCanvas() {
            addComponentListener(new ComponentAdapter() {
                @Override
                public void componentResized(ComponentEvent e) {
                    repaint();
                }
            });
        }

        @Override
        public void paint(Graphics g) {
            update(g);
        }

        @Override
        public void update(Graphics g) {
            if (offscreenImage == null ||
                    offscreenImage.getWidth() != getWidth() ||
                    offscreenImage.getHeight() != getHeight()) {
                offscreenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                offscreenGraphics = offscreenImage.createGraphics();
            }

            offscreenGraphics.setColor(getBackground());
            offscreenGraphics.fillRect(0, 0, getWidth(), getHeight());

            if (image != null) {
                aspectRatio = (double) image.getWidth() / image.getHeight();
                int displayHeight = (int) (getWidth() / aspectRatio);
                int y = (getHeight() - displayHeight) / 2;
                offscreenGraphics.drawImage(image, 0, y, getWidth(), displayHeight, this);
            }

            g.drawImage(offscreenImage, 0, 0, this);
        }

        public void setImage(BufferedImage image) {
            this.image = image;
            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(getWidth(), getHeight());
        }

        @Override
        public void invalidate() {
            super.invalidate();
            setSize(getWidth(), getHeight());
        }
    }

    // 停止摄像头
    private void stopCamera() {
        if (!isCameraOn) return;

        if (cameraTimer != null) {
            cameraTimer.stop();
            cameraTimer = null;
        }

        if (grabber != null) {
            try {
                grabber.stop();
                grabber.release();
            } catch (FrameGrabber.Exception ex) {
                ex.printStackTrace();
            }
            grabber = null;
        }

        if (cameraPanel.getComponentCount() > 0) {
            cameraPanel.remove(0);
        }
        cameraLabel.setText("摄像头已关闭");
        cameraPanel.add(cameraLabel, BorderLayout.CENTER);
        cameraPanel.revalidate();
        cameraPanel.repaint();

        isCameraOn = false;
    }

    // 绘制网格与坐标系
    private void drawGrid(Graphics g) {
        g.setColor(Color.LIGHT_GRAY);

        for (int i = 0; i <= BOARD_SIZE; i += 20) {
            g.drawLine(0, i, BOARD_SIZE, i);
            g.drawLine(i, 0, i, BOARD_SIZE);
        }

        g.setColor(Color.DARK_GRAY);
        Font font = new Font("Microsoft YaHei", Font.PLAIN, 12);
        g.setFont(font);
        FontMetrics fm = g.getFontMetrics();
        int labelW = fm.stringWidth("北");
        int labelH = fm.getHeight();

        int center = BOARD_SIZE / 2;
        g.drawString("北", center - labelW/2, 20);
        g.drawString("南", center - labelW/2, BOARD_SIZE - 10);
        g.drawString("西", 10, center + labelH/4);
        g.drawString("东", BOARD_SIZE - 10 - labelW, center + labelH/4);

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);
        g2d.setStroke(new BasicStroke(2));
        int crossSize = 10;
        g2d.drawLine(center - crossSize/2, center, center + crossSize/2, center);
        g2d.drawLine(center, center - crossSize/2, center, center + crossSize/2);
    }

    // 屏幕坐标转逻辑坐标
    private Point convertToLogicalCoordinates(Point screenPoint) {
        int center = BOARD_SIZE / 2;
        int logicalX = screenPoint.x - center;
        int logicalY = center - screenPoint.y;
        return new Point(logicalX, logicalY);
    }

    // 绘制目的地点
    private void drawDestination(Graphics g) {
        if (destination != null) {
            int center = BOARD_SIZE / 2;
            int flagX = center + destination.x;
            int flagY = center - destination.y;

            g.setColor(Color.BLACK);
            g.drawLine(flagX, flagY, flagX, flagY - 30);

            Polygon flag = new Polygon();
            flag.addPoint(flagX, flagY - 30);
            flag.addPoint(flagX + 20, flagY - 25);
            flag.addPoint(flagX, flagY - 20);
            g.setColor(Color.RED);
            g.fillPolygon(flag);
            g.setColor(Color.BLACK);
            g.drawPolygon(flag);
        }
    }

    // 绘制障碍物
    private void drawObstacles(Graphics g) {
        if (obstacles != null && !obstacles.isEmpty()) {
            int center = BOARD_SIZE / 2;

            for (Point obstacle : obstacles) {
                int x = center + obstacle.x;
                int y = center - obstacle.y;

                // 绘制障碍物（40*40的正方形）
                g.setColor(Color.BLACK);
                g.fillRect(x - 20, y - 20, 40, 40);

                // 添加障碍物标签
                g.setFont(new Font("Microsoft YaHei", Font.PLAIN, 11));
                g.setColor(Color.WHITE);
                g.drawString("障碍物", x - 15, y + 5);
            }
        }
    }

    // 绘制小车（20*30的长方形，车头有车灯）
    private void drawCar(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 小车尺寸（宽20，长30）
        int carWidth = 20;
        int carLength = 30;

        // 车灯尺寸
        int lightSize = 8;
        int lightOffset = carLength / 2;

        int center = BOARD_SIZE / 2;
        int carX = center + logicalX;
        int carY = center - logicalY;

        // 设置小车颜色（移动时为绿色，静止时为红色）
        // 修改：自动移动时也显示绿色
        // 设置小车颜色（移动时为蓝色，静止时为红色）
        g2d.setColor((isMoving || autoMoveTimer.isRunning()) ?
                new Color(52, 152, 219) :    // 蓝色（移动/自动移动）
                new Color(231, 76, 60));     // 红色（静止）

        // 根据方向绘制小车
        switch (direction) {
            case "北":
                // 绘制车身
                g2d.fillRect(carX - carWidth/2, carY - carLength/2, carWidth, carLength);

                // 绘制车灯
                g2d.setColor(isLightOn ? Color.YELLOW : Color.BLACK);
                g2d.fillOval(carX - carWidth/3 - lightSize/2, carY - carLength/2 - lightOffset/2, lightSize, lightSize);
                g2d.fillOval(carX + carWidth/3 - lightSize/2, carY - carLength/2 - lightOffset/2, lightSize, lightSize);
                break;

            case "东":
                // 绘制车身
                g2d.fillRect(carX - carLength/2, carY - carWidth/2, carLength, carWidth);

                // 绘制车灯
                g2d.setColor(isLightOn ? Color.YELLOW : Color.BLACK);
                g2d.fillOval(carX + carLength/2 - lightOffset/2, carY - carWidth/3 - lightSize/2, lightSize, lightSize);
                g2d.fillOval(carX + carLength/2 - lightOffset/2, carY + carWidth/3 - lightSize/2, lightSize, lightSize);
                break;

            case "南":
                // 绘制车身
                g2d.fillRect(carX - carWidth/2, carY - carLength/2, carWidth, carLength);

                // 绘制车灯
                g2d.setColor(isLightOn ? Color.YELLOW : Color.BLACK);
                g2d.fillOval(carX - carWidth/3 - lightSize/2, carY + carLength/2 - lightOffset/2, lightSize, lightSize);
                g2d.fillOval(carX + carWidth/3 - lightSize/2, carY + carLength/2 - lightOffset/2, lightSize, lightSize);
                break;

            case "西":
                // 绘制车身
                g2d.fillRect(carX - carLength/2, carY - carWidth/2, carLength, carWidth);

                // 绘制车灯
                g2d.setColor(isLightOn ? Color.YELLOW : Color.BLACK);
                g2d.fillOval(carX - carLength/2 + lightOffset/2, carY - carWidth/3 - lightSize/2, lightSize, lightSize);
                g2d.fillOval(carX - carLength/2 + lightOffset/2, carY + carWidth/3 - lightSize/2, lightSize, lightSize);
                break;
        }

        // 绘制方向指示
        g2d.setColor(Color.WHITE);
        FontMetrics fm = g2d.getFontMetrics();
        int textWidth = fm.stringWidth(direction);
        g2d.drawString(direction, carX - textWidth/2, carY + 5);
    }

    // 绘制轨迹
    private void drawTrajectory(Graphics g) {
        if (trajectory.size() < 2) return;

        g.setColor(Color.BLUE);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setStroke(new BasicStroke(2));

        int center = BOARD_SIZE / 2;
        for (int i = 0; i < trajectory.size() - 1; i++) {
            int[] p1 = trajectory.get(i);
            int[] p2 = trajectory.get(i + 1);
            g2d.drawLine(center + p1[0], center - p1[1], center + p2[0], center - p2[1]);
        }
    }

    // 处理方向
    private void handleDirection(String dir) {
        direction = dir;
        repaint();
    }

    // 移动小车
    private void moveForward(int step) {
        // 记录当前位置
        trajectory.add(new int[]{logicalX, logicalY});

        // 检查移动是否会碰到障碍物
        int newX = logicalX;
        int newY = logicalY;

        switch (direction) {
            case "北":
                newY += step;
                break;
            case "东":
                newX += step;
                break;
            case "南":
                newY -= step;
                break;
            case "西":
                newX -= step;
                break;
        }

        // 如果移动到障碍物，不执行移动
        if (!isPositionBlocked(newX, newY)) {
            logicalX = newX;
            logicalY = newY;
        } else {
            addCommand("前方有障碍物，无法移动");
        }

        // 边界检查
        checkBounds();
        repaint();
    }

    // 检查位置是否被障碍物阻挡（考虑障碍物尺寸）
    private boolean isPositionBlocked(int x, int y) {
        // 障碍物尺寸为40*40，所以检测范围设为20
        int detectionRange = 20;

        for (Point obstacle : obstacles) {
            if (Math.abs(obstacle.x - x) <= detectionRange &&
                    Math.abs(obstacle.y - y) <= detectionRange) {
                return true;
            }
        }

        return false;
    }

    // 自动移动到目的地
    private void autoMoveToDestination() {
        if (destination == null) return;

        // 记录当前位置
        trajectory.add(new int[]{logicalX, logicalY});

        int dx = destination.x - logicalX;
        int dy = destination.y - logicalY;

        // 检查是否到达目的地
        if (Math.abs(dx) <= speed && Math.abs(dy) <= speed) {
            logicalX = destination.x;
            logicalY = destination.y;
            autoMoveTimer.stop();
            startStopBtn.setText("开始");
            addCommand("到达目的地");
            repaint();
            return;
        }

        // A*算法规划路径
        List<Node> path = findPath(logicalX, logicalY, destination.x, destination.y);
        if (path != null && path.size() > 1) {
            // 获取下一个节点
            Node nextNode = path.get(1);
            int nextX = nextNode.x;
            int nextY = nextNode.y;

            // 确定移动方向
            if (nextX > logicalX) {
                direction = "东";
            } else if (nextX < logicalX) {
                direction = "西";
            } else if (nextY > logicalY) {
                direction = "北";
            } else {
                direction = "南";
            }

            // 移动到下一个节点
            logicalX = nextX;
            logicalY = nextY;
        } else {
            // 如果找不到路径，尝试简单的障碍物绕行
            addCommand("无法找到直达路径，尝试绕行");
            simpleAvoidance();
        }

        // 边界检查
        checkBounds();
        repaint();
    }

    // A*寻路算法
    private List<Node> findPath(int startX, int startY, int targetX, int targetY) {
        PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(node -> node.f));
        Set<Node> closedSet = new HashSet<>();

        Node startNode = new Node(startX, startY);
        Node targetNode = new Node(targetX, targetY);

        openSet.add(startNode);

        while (!openSet.isEmpty()) {
            Node currentNode = openSet.poll();
            closedSet.add(currentNode);

            // 到达目标节点
            if (currentNode.equals(targetNode)) {
                return retracePath(startNode, currentNode);
            }

            // 获取相邻节点
            List<Node> neighbors = getNeighbors(currentNode);
            for (Node neighbor : neighbors) {
                // 如果是障碍物或已访问，跳过
                if (isPositionBlocked(neighbor.x, neighbor.y) || closedSet.contains(neighbor)) {
                    continue;
                }

                // 计算新的移动成本
                int newMovementCostToNeighbor = currentNode.g + getDistance(currentNode, neighbor);
                if (newMovementCostToNeighbor < neighbor.g || !openSet.contains(neighbor)) {
                    neighbor.g = newMovementCostToNeighbor;
                    neighbor.h = getDistance(neighbor, targetNode);
                    neighbor.f = neighbor.g + neighbor.h;
                    neighbor.parent = currentNode;

                    if (!openSet.contains(neighbor)) {
                        openSet.add(neighbor);
                    }
                }
            }
        }

        return null; // 没有找到路径
    }

    // 回溯路径
    private List<Node> retracePath(Node startNode, Node endNode) {
        List<Node> path = new ArrayList<>();
        Node currentNode = endNode;

        while (currentNode != startNode) {
            path.add(currentNode);
            currentNode = currentNode.parent;
        }
        Collections.reverse(path);
        return path;
    }

    // 获取相邻节点
    private List<Node> getNeighbors(Node node) {
        List<Node> neighbors = new ArrayList<>();
        int x = node.x;
        int y = node.y;

        // 定义可以移动的方向（上下左右）
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

        for (int[] dir : directions) {
            int nx = x + dir[0];
            int ny = y + dir[1];

            // 检查边界
            int max = BOARD_SIZE / 2 - 30;
            if (nx >= -max && nx <= max && ny >= -max && ny <= max) {
                neighbors.add(new Node(nx, ny));
            }
        }

        return neighbors;
    }

    // 计算两个节点之间的距离
    private int getDistance(Node nodeA, Node nodeB) {
        int dstX = Math.abs(nodeA.x - nodeB.x);
        int dstY = Math.abs(nodeA.y - nodeB.y);
        return dstX + dstY; // 曼哈顿距离
    }

    // 简单的障碍物绕行逻辑
    private void simpleAvoidance() {
        // 尝试向右转
        switch (direction) {
            case "北":
                direction = "东";
                if (!isPositionBlocked(logicalX + speed, logicalY)) {
                    logicalX += speed;
                } else {
                    direction = "南";
                    if (!isPositionBlocked(logicalX, logicalY - speed)) {
                        logicalY -= speed;
                    } else {
                        direction = "西";
                        if (!isPositionBlocked(logicalX - speed, logicalY)) {
                            logicalX -= speed;
                        }
                    }
                }
                break;
            case "东":
                direction = "南";
                if (!isPositionBlocked(logicalX, logicalY - speed)) {
                    logicalY -= speed;
                } else {
                    direction = "西";
                    if (!isPositionBlocked(logicalX - speed, logicalY)) {
                        logicalX -= speed;
                    } else {
                        direction = "北";
                        if (!isPositionBlocked(logicalX, logicalY + speed)) {
                            logicalY += speed;
                        }
                    }
                }
                break;
            case "南":
                direction = "西";
                if (!isPositionBlocked(logicalX - speed, logicalY)) {
                    logicalX -= speed;
                } else {
                    direction = "北";
                    if (!isPositionBlocked(logicalX, logicalY + speed)) {
                        logicalY += speed;
                    } else {
                        direction = "东";
                        if (!isPositionBlocked(logicalX + speed, logicalY)) {
                            logicalX += speed;
                        }
                    }
                }
                break;
            case "西":
                direction = "北";
                if (!isPositionBlocked(logicalX, logicalY + speed)) {
                    logicalY += speed;
                } else {
                    direction = "东";
                    if (!isPositionBlocked(logicalX + speed, logicalY)) {
                        logicalX += speed;
                    } else {
                        direction = "南";
                        if (!isPositionBlocked(logicalX, logicalY - speed)) {
                            logicalY -= speed;
                        }
                    }
                }
                break;
        }
    }

    // 路径节点类
    private static class Node {
        int x, y;
        int g, h, f;
        Node parent;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node = (Node) o;
            return x == node.x && y == node.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }

    // 边界检查
    private void checkBounds() {
        int max = BOARD_SIZE / 2 - 30; // 留一些边距
        logicalX = Math.max(-max, Math.min(max, logicalX));
        logicalY = Math.max(-max, Math.min(max, logicalY));
    }

    // 重置方向
    private void reset() {
        direction = "北";
        repaint();
    }

    // 重置小车位置
    private void resetCar() {
        logicalX = 0;
        logicalY = 0;
        direction = "北";
        trajectory.clear();
        addCommand("小车已重置到原点");
        repaint();
    }

    // 新增：完全重置所有内容
    private void resetAll() {
        logicalX = 0;
        logicalY = 0;
        direction = "北";
        speed = 1;
        trajectory.clear();
        destination = null;
        obstacles.clear();
        isLightOn = false;
        showTrajectory = true;
        annotationMode = AnnotationMode.NONE;

        // 停止所有定时器
        if (moveTimer != null && moveTimer.isRunning()) {
            moveTimer.stop();
        }
        if (autoMoveTimer != null && autoMoveTimer.isRunning()) {
            autoMoveTimer.stop();
            startStopBtn.setText("开始");
        }

        addCommand("已重置所有内容：位置、方向、速度、轨迹、目的地、障碍物、车灯");
        repaint();
    }

    @Override
    public void dispose() {
        // 新增：窗口关闭时释放资源
        if (voiceSynthesizer != null) {
            voiceSynthesizer.stopPlay();
        }
        super.dispose();
    }

    // 主方法
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            CarSimulation app = new CarSimulation();
            app.setVisible(true);
        });
    }
}